#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

// 产品类
class Product {
public:
    // 添加产品部件
    void Add(std::string part) {
        parts_.push_back(part);
    }
    // 显示所有的产品部件
    void Show() {
        std::for_each(parts_.cbegin(),parts_.cend(),[](const std::string& s) {std::cout << s << " "; });
        std::cout << "\n";
    }
private:
    std::vector<std::string> parts_;
};

// 抽象建造者，并声明一个得到产品建造后结果的方法
class Builder {
    public:
    virtual ~Builder() = default;
    virtual void BuildPartA() = 0;
    virtual void BuildPartB() = 0;
    virtual Product* GetResult() = 0;
};

// 具体建造者类，实现Builder接口中的具体方法
class ConcreteBuilder1 : public Builder{
public:
    virtual void BuildPartA() {
        product_->Add("部件A");
    }
    virtual void BuildPartB() {
        product_->Add("部件B");
    }
    virtual Product* GetResult() {
        return product_;
    }
private:
    Product* product_ = new Product;
};

// 具体建造者类，实现Builder接口中的具体方法
class ConcreteBuilder2 : public Builder{
public:
    virtual void BuildPartA() {
        product_->Add("部件X");
    }
    virtual void BuildPartB() {
        product_->Add("部件Y");
    }
    virtual Product* GetResult() {
        return product_;
    }
private:
    Product* product_ = new Product;
};

// 指挥者类,指挥建造product的过程（控制构建各部分组件的顺序）
class Director {
    public:
    void Contruct (Builder* const builder) {
        builder->BuildPartA();
        builder->BuildPartB();
    }

};

int main() {
    std::cout << "hello constructor pattern!!!" << std::endl;
    // 用户并不需要知道具体的建造过程，只需指定建造product具体类型
    Director director;
    Builder* b1 = new ConcreteBuilder1;
    Builder* b2 = new ConcreteBuilder2;
    
    std::cout << "用ConcreteBuilder1的方法建造产品" << std::endl;
    director.Contruct(b1);
    Product* p1 = b1->GetResult();
    p1->Show();

    std::cout << "用ConcreteBuilder2的方法建造产品" << std::endl;
    director.Contruct(b2);
    Product* p2 = b2->GetResult();
    p2->Show();

    delete p2;
    delete p1;
    delete b2;
    delete b1;
    p2 = p1 = nullptr;
    b1 = b2 = nullptr;


    return 0;
}